﻿using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Smo;

namespace Microsoft.CTS.HSG
{
    /// <summary>
    /// This class specifies script engine scripting parameters.
    /// </summary>
    public sealed class ScriptEngineConfiguration
    {
        public string Instance { get; set; }
        public string Database { get; set; }
        public string FileName { get; set; }
        public bool AgentAlertJob { get; private set; }
        public bool AgentJobId { get; private set; }
        public bool AgentNotify { get; private set; }
        public bool AllowSystemObjects { get; private set; }
        public bool AnsiFile { get; private set; }
        public bool AnsiPadding { get; private set; }
        public bool AppendToFile { get; private set; }
        public int BatchSize { get; private set; }
        public bool Bindings { get; private set; }
        public bool ChangeTracking { get; private set; }
        public bool ClusteredIndexes { get; private set; }
        public bool ContinueScriptingOnError { get; private set; }
        public bool ConvertUserDefinedDataTypesToBaseType { get; private set; }
        public bool DdlBodyOnly { get; private set; }
        public bool DdlHeaderOnly { get; private set; }
        public bool Default { get; private set; }
        public bool DriAll { get; private set; }
        public bool DriAllConstraints { get; private set; }
        public bool DriAllKeys { get; private set; }
        public bool DriChecks { get; private set; }
        public bool DriClustered { get; private set; }
        public bool DriDefaults { get; private set; }
        public bool DriForeignKeys { get; private set; }
        public bool DriIncludeSystemNames { get; private set; }
        public bool DriIndexes { get; private set; }
        public bool DriNonClustered { get; private set; }
        public bool DriPrimaryKey { get; private set; }
        public bool DriUniqueKeys { get; private set; }
        public bool DriWithNoCheck { get; private set; }
        public Encoding Encoding { get; private set; }
        public bool EnforceScriptingOptions { get; private set; }
        public bool ExtendedProperties { get; private set; }
        public bool FullTextCatalogs  { get; private set; }
        public bool FullTextIndexes { get; private set; }
        public bool FullTextStopLists { get; private set; }
        public bool IncludeDatabaseContext { get; private set; }
        public bool IncludeDatabaseRoleMemberships { get; private set; }
        public bool IncludeFullTextCatalogRootPath { get; private set; }
        public bool IncludeHeaders { get; private set; }
        public bool IncludeIfNotExists  { get; private set; }
        public bool Indexes { get; private set; }
        public bool LoginSid { get; private set; }
        public bool Assemblies  { get; set; }
        public bool Collation { get; set; }
        public bool CommandTerminator { get; private set; }
        public bool ExecuteAs { get; set; }
        public bool FileGroup { get; private set; }
        public bool FileStream { get; private set; }
        public bool FileStreamColumn { get; private set; }
        public bool Identities { get; private set; }
        public bool IndexPartitioningSchemes { get; private set; }
        public bool MailProfileAccounts { get; private set; }
        public bool MailProfilePrincipals { get; private set; }
        public bool NonClusteredIndexes { get; private set; }
        public bool TablePartitioningSchemes { get; private set; }
        public bool Vardecimal { get; private set; }
        public bool ViewColumns { get; private set; }
        public bool XmlNamespaces { get; private set; }
        public bool OptimizerData  { get; set; }
        public bool Permissions  { get; private set; }
        public bool PrimaryObject { get; private set; }
        public bool SchemaQualify { get; private set; }
        public bool SchemaQualifyForeignKeysReferences { get; private set; }
        public bool ScriptBatchTerminator { get; private set; }
        public bool ScriptData { get; private set; }
        public bool ScriptDataCompression { get; private set; }
        public bool ScriptDrops { get; private set; }
        public bool ScriptOwner { get; private set; }
        public bool ScriptSchema { get; private set; }

        public bool Statistics
        {
            get
            {
                return this.OptimizerData;
            }

            private set { }
        }
        
        public SqlServerVersion TargetServerVersion { get; set; }
        public bool TimestampToBinary { get; private set; }
        public bool ToFileOnly { get; private set; }
        public bool Triggers { get; private set; }
        public bool WithDependencies { get; private set; }
        public bool XmlIndexes { get; private set; }
        public bool CopyAllObjects { get; private set; }
        public bool PrefetchObjects { get; private set; }
        public bool CopyAllLogins { get; private set; }

        /// <summary>
        /// Creates a new instance of the ScriptEngineConfiguration class.
        /// </summary>
        public ScriptEngineConfiguration()
        {
            //
            // Set the read-only properties.
            //

            this.AgentAlertJob = false;
            this.AgentJobId = false;
            this.AgentNotify = false;
            this.AllowSystemObjects = false;
            this.AnsiFile = false;
            this.AnsiPadding = true;
            this.BatchSize = 1;
            this.Bindings = false;
            this.ChangeTracking = false;
            this.ClusteredIndexes = true;
            this.ContinueScriptingOnError = true;
            this.ConvertUserDefinedDataTypesToBaseType = true;
            this.DdlBodyOnly = false;
            this.DdlHeaderOnly = false;
            this.Default = true;
            this.DriAll = true;
            this.DriAllConstraints = true;
            this.DriAllKeys = true;
            this.DriChecks = true;
            this.DriClustered = true;
            this.DriDefaults = true;
            this.DriForeignKeys = true;
            this.DriIncludeSystemNames = true;
            this.DriIndexes = true;
            this.DriNonClustered = true;
            this.DriPrimaryKey = true;
            this.DriUniqueKeys = true;
            this.DriWithNoCheck = true;
            this.Encoding = Encoding.Unicode;
            this.EnforceScriptingOptions = true;
            this.ExtendedProperties = true;
            this.IncludeDatabaseContext = true;
            this.IncludeDatabaseRoleMemberships = true;
            this.IncludeHeaders = true;
            this.IncludeIfNotExists = false;
            this.Indexes = true;
            this.LoginSid = false;
            this.CommandTerminator = true;
            this.ExecuteAs = true;
            this.FileGroup = true;
            this.FileStream = true;
            this.FileStreamColumn = true;
            this.Identities = true;
            this.IndexPartitioningSchemes = true;
            this.MailProfileAccounts = false;
            this.MailProfilePrincipals = false;
            this.NonClusteredIndexes = true;
            this.TablePartitioningSchemes = true;
            this.Vardecimal = true;
            this.ViewColumns = true;
            this.XmlNamespaces = true;
            this.PrimaryObject = true;
            this.SchemaQualify = true;
            this.SchemaQualifyForeignKeysReferences = true;
            this.ScriptBatchTerminator = true;
            this.ScriptData = false;
            this.ScriptDataCompression = true;
            this.ScriptDrops = false;
            this.ScriptOwner = true;
            this.ScriptSchema = true;
            this.Statistics = this.OptimizerData;
            this.TimestampToBinary = true;
            this.ToFileOnly = true;
            this.Triggers = true;
            this.WithDependencies = true;
            this.XmlIndexes = true;
            this.CopyAllObjects = true;
            this.PrefetchObjects = false;
            this.CopyAllLogins = true;
            this.AppendToFile = false;
            this.Permissions = true;
            this.FullTextCatalogs = true;
            this.FullTextIndexes = true;
            this.FullTextStopLists = true;
            this.IncludeFullTextCatalogRootPath = true;
            this.Collation = true;

        }

        /// <summary>
        /// Validates a ScriptEngineConfiguration instance
        /// </summary>
        /// <param name="config"></param>
        public static void ValidateConfiguration(
            ScriptEngineConfiguration config
            )
        {
            if (config == null)
            {
                throw new ArgumentNullException(
                    "config",
                    "The ScriptEngineConfiguration instance was null."
                    );
            }

            if (string.IsNullOrEmpty(config.Instance) != false)
            {
                throw new ArgumentException(
                    "A SQL Server instance must be specified.",
                    "ScriptEngineConfiguration.Instance"
                    );
            }

            if (string.IsNullOrEmpty(config.Database) != false)
            {
                throw new ArgumentException(
                    "A database name must be specified.",
                    "Config.Database"
                    );
            }

            if (string.IsNullOrEmpty(config.FileName) != false)
            {
                throw new ArgumentException(
                    "A file name must be specified.",
                    "config.FileName"
                    );
            }

            

            //
            // The directory must exist unless only a filename was specified.
            //

            string fileDirectoryName = Path.GetDirectoryName(
                config.FileName
                );

            if (string.IsNullOrEmpty(fileDirectoryName) == false)
            {
                if (Directory.Exists(fileDirectoryName) == false)
                {
                    string message = string.Format(
                        CultureInfo.InvariantCulture,
                        "The directory '{0}' does not exist and must be created.",
                        fileDirectoryName
                        );

                    throw new DirectoryNotFoundException(
                        message
                        );
                }
            }
        }
    }
}
